﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace WorkStation.Frameworks.Core.Util
{
    public class XmlUtil
    {
        #region 二进制序列化

        public static TObject FullCloneObject<TObject>(object obj) where TObject : class
        {
            using (MemoryStream ms = new MemoryStream())
            {
                BinSerializeObject(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                return BinDeserializeObject<TObject>(ms);
            }
        }

        public static TObject BinDeserializeObject<TObject>(string binFile) where TObject : class
        {
            using (FileStream fs = new FileStream(binFile, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                return BinDeserializeObject<TObject>(fs);
            }
        }

        public static TObject BinDeserializeObject<TObject>(Stream stream) where TObject : class
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf
                = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            return (TObject)bf.Deserialize(stream);
        }

        public static void BinSerializeObject(string binFile, object obj)
        {
            using (FileStream fs = new FileStream(binFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                BinSerializeObject(fs, obj);
            }
        }

        public static void BinSerializeObject(Stream stream, object obj)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf
                = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            bf.Serialize(stream, obj);
        }

        public static byte[] BinSerializeObject(object obj)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf
                    = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                bf.Serialize(stream, obj);

                return stream.ToArray();
            }
        }

        #endregion

        #region XSD对象读写

        /// <summary>
        /// * 从指定XML文件中反射读取XML(XSD)对象
        /// </summary>
        /// <typeparam name="TXsdObject">XSD对象类型</typeparam>
        /// <param name="xmlFile">XML文件路径</param>
        /// <returns>XSD对象实例</returns>
        public static TXsdObject DeserializeSchemaObjectFromFile<TXsdObject>(string xmlFile) where TXsdObject : class
        {
            return DeserializeSchemaObjectFromFile<TXsdObject>(xmlFile, null);
        }

        /// <summary>
        /// * 以指定文本编码从指定XML文件中反射读取XML(XSD)对象
        /// </summary>
        /// <typeparam name="TXsdObject">XSD对象类型</typeparam>
        /// <param name="xmlFile">XML文件路径</param>
        /// <param name="encoding">文本编码</param>
        /// <returns>XSD对象实例</returns>
        public static TXsdObject DeserializeSchemaObjectFromFile<TXsdObject>(string xmlFile, Encoding encoding) where TXsdObject : class
        {
            using (FileStream fs = new FileStream(xmlFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                XmlSerializer xs = new XmlSerializer(typeof(TXsdObject));

                xs.UnknownElement += new XmlElementEventHandler(xs_UnknownElement);
                xs.UnknownAttribute += new XmlAttributeEventHandler(xs_UnknownAttribute);
                xs.UnknownNode += new XmlNodeEventHandler(xs_UnknownNode);

                if (encoding == null)
                {
                    return xs.Deserialize(fs) as TXsdObject;
                }
                else
                {
                    using (StreamReader reader = new StreamReader(fs, encoding))
                    {
                        return xs.Deserialize(reader) as TXsdObject;
                    }
                }
            }
        }

        static void xs_UnknownNode(object sender, XmlNodeEventArgs e)
        {
#if DEBUG
            Console.WriteLine("{0} can't identify.", e.Name);
#endif
        }

        static void xs_UnknownAttribute(object sender, XmlAttributeEventArgs e)
        {
#if DEBUG
            Console.WriteLine("{0} can't identify.", e.Attr);
#endif
        }

        static void xs_UnknownElement(object sender, XmlElementEventArgs e)
        {
#if DEBUG
            Console.WriteLine("{0} can't identify.", e.Element);
#endif
        }

        /// <summary>
        /// * 从指定XML文本中反射读取XML(XSD)对象
        /// </summary>
        /// <typeparam name="TXsdObject">XSD对象类型</typeparam>
        /// <param name="xmlText">XML文本</param>
        /// <returns>XSD对象实例</returns>
        public static TXsdObject DeserializeSchemaObjectFromString<TXsdObject>(string xmlText)
        {
            XmlSerializer xs = new XmlSerializer(typeof(TXsdObject));

            using (StringReader reader = new StringReader(xmlText))
            {
                return (TXsdObject)xs.Deserialize(reader);
            }
        }

        /// <summary>
        /// * 将指定XSD对象序列化到指定XML文件
        /// </summary>
        /// <param name="xmlFile">目标XML文件</param>
        /// <param name="schemaObject">要序列化的对象</param>
        public static void SerializeSchemaObjectToFile(string xmlFile, object schemaObject)
        {
            SerializeSchemaObjectToFile(xmlFile, schemaObject, null);
        }

        /// <summary>
        /// * 以指定文本编码将指定XSD对象序列化到指定XML文件
        /// </summary>
        /// <param name="xmlFile">目标XML文件</param>
        /// <param name="schemaObject">要序列化的对象</param>
        /// <param name="encoding">文本编码</param>
        public static void SerializeSchemaObjectToFile(string xmlFile, object schemaObject, Encoding encoding)
        {
            using (FileStream fs = new FileStream(xmlFile, FileMode.Create, FileAccess.Write, FileShare.Read))
            {
                XmlSerializer xs = new XmlSerializer(schemaObject.GetType());

                xs.UnknownElement += new XmlElementEventHandler(xs_UnknownElement);
                xs.UnknownAttribute += new XmlAttributeEventHandler(xs_UnknownAttribute);
                xs.UnknownNode += new XmlNodeEventHandler(xs_UnknownNode);

                if (encoding == null)
                {
                    xs.Serialize(fs, schemaObject);
                }
                else
                {
                    using (StreamWriter writer = new StreamWriter(fs, encoding))
                    {
                        xs.Serialize(writer, schemaObject);
                    }
                }
            }
        }

        /// <summary>
        /// * 将指定XSD对象序列化为字符串
        /// </summary>
        /// <param name="schemaObject">要序列化的对象</param>
        /// <returns>序列化后的字符串</returns>
        public static string SerializeSchemaObjectToString(object schemaObject)
        {
            StringBuilder builder = new StringBuilder();

            XmlSerializer xs = new XmlSerializer(schemaObject.GetType());

            using (TextWriter writer = new StringWriter(builder))
            {
                xs.Serialize(writer, schemaObject);

                writer.Flush();
            }

            return builder.ToString();
        }

        #endregion
    }
}
